1   /*
2    * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /*
25   * @test
26   * @bug 4074599 4939441
27   * @summary Tests for {Math, StrictMath}.log10
28   * @author Joseph D. Darcy
29   */
30  
31  import sun.misc.FpUtils;
32  import sun.misc.DoubleConsts;
33  
34  public class Log10Tests {
35      private Log10Tests(){}
36  
37      static final double infinityD = Double.POSITIVE_INFINITY;
38      static final double NaNd = Double.NaN;
39      static final double LN_10 = StrictMath.log(10.0);
40  
41      // Initialize shared random number generator
42      static java.util.Random rand = new java.util.Random(0L);
43  
44      static int testLog10Case(double input, double expected) {
45          int failures=0;
46  
47          failures+=Tests.test("Math.log10(double)", input,
48                               Math.log10(input), expected);
49  
50          failures+=Tests.test("StrictMath.log10(double)", input,
51                               StrictMath.log10(input), expected);
52  
53          return failures;
54      }
55  
56      static int testLog10() {
57          int failures = 0;
58  
59          double [][] testCases = {
60              {Double.NaN,                NaNd},
61              {Double.longBitsToDouble(0x7FF0000000000001L),      NaNd},
62              {Double.longBitsToDouble(0xFFF0000000000001L),      NaNd},
63              {Double.longBitsToDouble(0x7FF8555555555555L),      NaNd},
64              {Double.longBitsToDouble(0xFFF8555555555555L),      NaNd},
65              {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL),      NaNd},
66              {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL),      NaNd},
67              {Double.longBitsToDouble(0x7FFDeadBeef00000L),      NaNd},
68              {Double.longBitsToDouble(0xFFFDeadBeef00000L),      NaNd},
69              {Double.longBitsToDouble(0x7FFCafeBabe00000L),      NaNd},
70              {Double.longBitsToDouble(0xFFFCafeBabe00000L),      NaNd},
71              {Double.NEGATIVE_INFINITY,  NaNd},
72              {-8.0,                      NaNd},
73              {-1.0,                      NaNd},
74              {-DoubleConsts.MIN_NORMAL,  NaNd},
75              {-Double.MIN_VALUE,         NaNd},
76              {-0.0,                      -infinityD},
77              {+0.0,                      -infinityD},
78              {+1.0,                      0.0},
79              {Double.POSITIVE_INFINITY,  infinityD},
80          };
81  
82          // Test special cases
83          for(int i = 0; i < testCases.length; i++) {
84              failures += testLog10Case(testCases[i][0],
85                                            testCases[i][1]);
86          }
87  
88          // Test log10(10^n) == n for integer n; 10^n, n < 0 is not
89          // exactly representable as a floating-point value -- up to
90          // 10^22 can be represented exactly
91          double testCase = 1.0;
92          for(int i = 0; i < 23; i++) {
93              failures += testLog10Case(testCase, i);
94              testCase *= 10.0;
95          }
96  
97          // Test for gross inaccuracy by comparing to log; should be
98          // within a few ulps of log(x)/log(10)
99          for(int i = 0; i < 10000; i++) {
100             double input = Double.longBitsToDouble(rand.nextLong());
101             if(! FpUtils.isFinite(input))
102                 continue; // avoid testing NaN and infinite values
103             else {
104                 input = Math.abs(input);
105 
106                 double expected = StrictMath.log(input)/LN_10;
107                 if( ! FpUtils.isFinite(expected))
108                     continue; // if log(input) overflowed, try again
109                 else {
110                     double result;
111 
112                     if( Math.abs(((result=Math.log10(input)) - expected)/Math.ulp(expected)) > 3) {
113                         failures++;
114                         System.err.println("For input " + input +
115                                            ", Math.log10 was more than 3 ulps different from " +
116                                            "log(input)/log(10): log10(input) = " + result +
117                                            "\tlog(input)/log(10) = " + expected);
118                     }
119 
120                     if( Math.abs(((result=StrictMath.log10(input)) - expected)/Math.ulp(expected)) > 3) {
121                         failures++;
122                         System.err.println("For input " + input +
123                                            ", StrictMath.log10 was more than 3 ulps different from " +
124                                            "log(input)/log(10): log10(input) = " + result +
125                                            "\tlog(input)/log(10) = " + expected);
126                     }
127 
128 
129                 }
130             }
131         }
132 
133         // Test for accuracy and monotonicity near log10(1.0).  From
134         // the Taylor expansion of log,
135         // log10(1+z) ~= (z -(z^2)/2)/LN_10;
136         {
137             double neighbors[] =        new double[40];
138             double neighborsStrict[] =  new double[40];
139             double z = Double.NaN;
140 
141             // Test inputs greater than 1.0.
142             neighbors[0] =              Math.log10(1.0);
143             neighborsStrict[0] =        StrictMath.log10(1.0);
144 
145             double input[] =  new double[40];
146             int half = input.length/2;
147 
148 
149             // Initialize input to the 40 consecutive double values
150             // "centered" at 1.0.
151             double up = Double.NaN;
152             double down = Double.NaN;
153             for(int i = 0; i < half; i++) {
154                 if (i == 0) {
155                     input[half] = 1.0;
156                     up   = FpUtils.nextUp(1.0);
157                     down = FpUtils.nextDown(1.0);
158                 } else {
159                     input[half + i] = up;
160                     input[half - i] = down;
161                     up   = FpUtils.nextUp(up);
162                     down = FpUtils.nextDown(down);
163                 }
164             }
165             input[0] = FpUtils.nextDown(input[1]);
166 
167             for(int i = 0; i < neighbors.length; i++) {
168                 neighbors[i] =          Math.log10(input[i]);
169                 neighborsStrict[i] =    StrictMath.log10(input[i]);
170 
171                 // Test accuracy.
172                 z = input[i] - 1.0;
173                 double expected = (z - (z*z)*0.5)/LN_10;
174                 if ( Math.abs(neighbors[i] - expected ) > 3*Math.ulp(expected) ) {
175                     failures++;
176                     System.err.println("For input near 1.0 " + input[i] +
177                                        ", Math.log10(1+z) was more than 3 ulps different from " +
178                                        "(z-(z^2)/2)/ln(10): log10(input) = " + neighbors[i] +
179                                        "\texpected about = " + expected);
180                 }
181 
182                 if ( Math.abs(neighborsStrict[i] - expected ) > 3*Math.ulp(expected) ) {
183                     failures++;
184                     System.err.println("For input near 1.0 " + input[i] +
185                                        ", StrictMath.log10(1+z) was more than 3 ulps different from " +
186                                        "(z-(z^2)/2)/ln(10): log10(input) = " + neighborsStrict[i] +
187                                        "\texpected about = " + expected);
188                 }
189 
190                 // Test monotonicity
191                 if( i > 0) {
192                     if( neighbors[i-1] > neighbors[i] ) {
193                         failures++;
194                         System.err.println("Monotonicity failure for Math.log10  at " + input[i] +
195                                            " and prior value.");
196                     }
197 
198                     if( neighborsStrict[i-1] > neighborsStrict[i] ) {
199                         failures++;
200                         System.err.println("Monotonicity failure for StrictMath.log10  at " + input[i] +
201                                            " and prior value.");
202                     }
203                 }
204             }
205 
206         }
207 
208         return failures;
209     }
210 
211     public static void main(String argv[]) {
212         int failures = 0;
213 
214         failures += testLog10();
215 
216         if (failures > 0) {
217             System.err.println("Testing log10 incurred "
218                                + failures + " failures.");
219             throw new RuntimeException();
220         }
221     }
222 
223 }